/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

#include <gtest/gtest.h>

#include <limits.h>

#include "x_ring.h"

class TestRing : public ::testing::Test
{
protected:
    void SetUp() {};

    void TearDown() {};
};

TEST_F(TestRing, ring_create)
{
    ring_t *ring = ring_create(16);
    EXPECT_NE(ring, nullptr);
    EXPECT_EQ(ring->size, 16);
    EXPECT_EQ(ring->head, 0);
    EXPECT_EQ(ring->tail, 0);
    EXPECT_NE(ring->buf, nullptr);
    ring_destroy(ring);

    ring = ring_create(15);
    EXPECT_EQ(ring, nullptr);
}

TEST_F(TestRing, ring_destroy)
{
    ring_t *ring = ring_create(16);
    ring_destroy(ring);

    ring_destroy(nullptr);
}

TEST_F(TestRing, ring_init)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    int ret = ring_init(&ring, buf, 16);
    EXPECT_EQ(ret, 0);
    EXPECT_EQ(ring.size, 16);
    EXPECT_EQ(ring.head, 0);
    EXPECT_EQ(ring.tail, 0);
    EXPECT_EQ(ring.buf, buf);

    ret = ring_init(&ring, nullptr, 16);
    EXPECT_EQ(ret, -1);

    ret = ring_init(nullptr, buf, 16);
    EXPECT_EQ(ret, -1);

    ret = ring_init(&ring, buf, 15);
    EXPECT_EQ(ret, -1);
}

TEST_F(TestRing, ring_reset)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    ring.head = 8;
    ring.tail = 8;
    ring_reset(&ring);
    EXPECT_EQ(ring.head, 0);
    EXPECT_EQ(ring.tail, 0);
}

TEST_F(TestRing, ring_len)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    ring.head = 8;
    ring.tail = 4;
    EXPECT_EQ(ring_len(&ring), 4);
}

TEST_F(TestRing, ring_empty)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    EXPECT_EQ(ring_empty(&ring), true);
    ring.head = 8;
    ring.tail = 4;
    EXPECT_EQ(ring_empty(&ring), false);
}

TEST_F(TestRing, ring_full)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    EXPECT_EQ(ring_full(&ring), false);
    ring.head = 8;
    ring.tail = 4;
    EXPECT_EQ(ring_full(&ring), false);
    ring.head = 16;
    ring.tail = 0;
    EXPECT_EQ(ring_full(&ring), true);
}

TEST_F(TestRing, ring_peek)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    ring.head = 8;
    ring.tail = 4;
    buf[4] = 0x12;
    buf[5] = 0x34;
    buf[6] = 0x56;
    buf[7] = 0x78;
    EXPECT_EQ(ring_peek(&ring, 0), 0x12);
    EXPECT_EQ(ring_peek(&ring, 1), 0x34);
    EXPECT_EQ(ring_peek(&ring, 2), 0x56);
    EXPECT_EQ(ring_peek(&ring, 3), 0x78);
}

TEST_F(TestRing, ring_putc)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    EXPECT_EQ(ring_putc(&ring, 0x12), 1);
    EXPECT_EQ(ring.head, 1);
    EXPECT_EQ(ring.buf[0], 0x12);
}

TEST_F(TestRing, ring_putc_force)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    ring.head = 16;
    ring.tail = 0;
    EXPECT_EQ(ring_putc_force(&ring, 0x12), 1);
    EXPECT_EQ(ring.head, 17);
    EXPECT_EQ(ring.tail, 1);
    EXPECT_EQ(ring.buf[0], 0x12);
}

TEST_F(TestRing, ring_put)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    unsigned char data[16] = {0x12, 0x34, 0x56, 0x78};
    EXPECT_EQ(ring_put(&ring, data, 4), 4);
    EXPECT_EQ(ring.head, 4);
    EXPECT_EQ(ring.buf[0], 0x12);
    EXPECT_EQ(ring.buf[1], 0x34);
    EXPECT_EQ(ring.buf[2], 0x56);
    EXPECT_EQ(ring.buf[3], 0x78);
}

TEST_F(TestRing, ring_put_force)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    ring.head = 16;
    ring.tail = 0;
    unsigned char data[16] = {0x12, 0x34, 0x56, 0x78};
    EXPECT_EQ(ring_put_force(&ring, data, 4), 4);
    EXPECT_EQ(ring.head, 20);
    EXPECT_EQ(ring.tail, 4);
    EXPECT_EQ(ring.buf[0], 0x12);
    EXPECT_EQ(ring.buf[1], 0x34);
    EXPECT_EQ(ring.buf[2], 0x56);
    EXPECT_EQ(ring.buf[3], 0x78);
}

TEST_F(TestRing, ring_getc)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    ring.head = 4;
    ring.tail = 0;
    unsigned char byte;
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0);
    EXPECT_EQ(ring.tail, 1);
}

TEST_F(TestRing, ring_get)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    ring.head = 4;
    ring.tail = 0;
    unsigned char data[16] = {0};
    EXPECT_EQ(ring_get(&ring, data, 4), 4);
    EXPECT_EQ(data[0], 0);
    EXPECT_EQ(data[1], 0);
    EXPECT_EQ(data[2], 0);
    EXPECT_EQ(data[3], 0);
    EXPECT_EQ(ring.tail, 4);
}

TEST_F(TestRing, ring_putc_empty)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    unsigned char byte;
    EXPECT_EQ(ring_putc(&ring, 0x12), 1);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0x12);
    EXPECT_EQ(ring_getc(&ring, &byte), 0);
}

TEST_F(TestRing, ring_putc_full)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    unsigned char byte;
    for (int i = 0; i < 16; ++i) {
        EXPECT_EQ(ring_putc(&ring, i), 1);
    }
    EXPECT_EQ(ring_putc(&ring, 0x12), 0);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 1);
}

TEST_F(TestRing, ring_put_empty)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    unsigned char data[16] = {0x12, 0x34, 0x56, 0x78};
    unsigned char byte;
    EXPECT_EQ(ring_put(&ring, data, 4), 4);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0x12);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0x34);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0x56);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0x78);
    EXPECT_EQ(ring_getc(&ring, &byte), 0);
}

TEST_F(TestRing, ring_put_full)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    unsigned char data[17] = {0x12, 0x34, 0x56, 0x78};
    unsigned char byte;
    EXPECT_EQ(ring_put(&ring, data, 16), 16);
    EXPECT_EQ(ring_put(&ring, data, 1), 0);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0x12);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0x34);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0x56);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0x78);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0);
}

TEST_F(TestRing, ring_put_force_empty)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    unsigned char byte;
    EXPECT_EQ(ring_putc_force(&ring, 0x12), 1);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0x12);
    EXPECT_EQ(ring_getc(&ring, &byte), 0);
}

TEST_F(TestRing, ring_put_force_full)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    unsigned char byte;
    for (int i = 0; i < 16; ++i) {
        EXPECT_EQ(ring_putc_force(&ring, i), 1);
    }
    EXPECT_EQ(ring.head, 16);
    EXPECT_EQ(ring.tail, 0);

    EXPECT_EQ(ring_putc_force(&ring, 0x12), 1);
    EXPECT_EQ(ring.head, 17);
    EXPECT_EQ(ring.tail, 1);

    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 1);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 2);
}

TEST_F(TestRing, ring_put_pos_overflow)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    ring.head = SIZE_MAX - 2;
    ring.tail = SIZE_MAX - 3;
    unsigned char data[16] = {0x12, 0x34, 0x56, 0x78};
    EXPECT_EQ(ring_put(&ring, data, 4), 4);
    EXPECT_EQ(ring.head, 1);
    EXPECT_EQ(ring.tail, SIZE_MAX - 3);
    unsigned char byte;
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0x12);
}

TEST_F(TestRing, ring_putc_pos_overflow)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    ring.head = SIZE_MAX;
    ring.tail = SIZE_MAX - 3;
    EXPECT_EQ(ring_putc(&ring, 0x12), 1);
    EXPECT_EQ(ring.head, 0);
    EXPECT_EQ(ring.tail, SIZE_MAX - 3);
    unsigned char byte;
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0);
}

TEST_F(TestRing, ring_put_overflow)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    ring.head = SIZE_MAX - 2;
    ring.tail = SIZE_MAX - 3;
    unsigned char data[16] = {0x12, 0x34, 0x56, 0x78};
    EXPECT_EQ(ring_put(&ring, data, 4), 4);
    EXPECT_EQ(ring.head, 1);
    EXPECT_EQ(ring.tail, SIZE_MAX - 3);
    unsigned char byte;
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0);
    EXPECT_EQ(ring_getc(&ring, &byte), 1);
    EXPECT_EQ(byte, 0x12);
}

TEST_F(TestRing, ring_getc_empty)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    unsigned char byte;
    EXPECT_EQ(ring_getc(&ring, &byte), 0);
}

TEST_F(TestRing, ring_get_empty)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    unsigned char data[16] = {0};
    EXPECT_EQ(ring_get(&ring, data, 4), 0);
}

TEST_F(TestRing, ring_getc_full)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    unsigned char byte;
    for (int i = 0; i < 16; ++i) {
        EXPECT_EQ(ring_putc_force(&ring, i), 1);
    }
    for (int i = 0; i < 16; ++i) {
        EXPECT_EQ(ring_getc(&ring, &byte), 1);
        EXPECT_EQ(byte, i);
    }
    EXPECT_EQ(ring_getc(&ring, &byte), 0);
}

TEST_F(TestRing, ring_get_full)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    unsigned char data[16] = {0};
    for (int i = 0; i < 16; ++i) {
        EXPECT_EQ(ring_putc_force(&ring, i), 1);
    }
    EXPECT_EQ(ring_get(&ring, data, 16), 16);
    for (int i = 0; i < 16; ++i) {
        EXPECT_EQ(data[i], i);
    }
    EXPECT_EQ(ring_get(&ring, data, 4), 0);
}

TEST_F(TestRing, ring_get_around)
{
    unsigned char buf[16] = {0};
    ring_t ring;
    ring_init(&ring, buf, 16);
    ring.head = 14;
    ring.tail = 14;
    for (int i = 0; i < 16; ++i) {
        EXPECT_EQ(ring_putc(&ring, i), 1);
    }
    unsigned char data[16] = {0};
    EXPECT_EQ(ring_get(&ring, data, 16), 16);
    for (int i = 0; i < 16; ++i) {
        EXPECT_EQ(data[i], i);
    }
}
